using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Admin.NET.Application.Entity;
using Admin.NET.Application.Entity.Business;
using Admin.NET.Application.Excel;
using Admin.NET.Core;
using Furion;
using Furion.DataEncryption;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Mapster;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;

namespace Admin.NET.Application;

/// <summary>
/// Owner服务
/// </summary>
[ApiDescriptionSettings(new string[] { "业务应用" }, Order = 100)]
public class OwnerService : IDynamicApiController, ITransient, IPrivateDependency
{
	private readonly SqlSugarRepository<Owner> _rep;

	private readonly UserManager _userManager;

	public OwnerService(SqlSugarRepository<Owner> rep, UserManager userManager)
	{
		_rep = rep;
		_userManager = userManager;
	}

	/// <summary>
	/// 分页查询业主
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpGet("/owner/page")]
	public async Task<dynamic> Page([FromQuery] OwnerInput input)
	{
		ISugarQueryable<Owner> query = _rep.Context.Queryable<Owner>().WhereIF(!string.IsNullOrWhiteSpace(input.Name), (Owner u) => u.Name.Contains(input.Name.Trim())).WhereIF(!string.IsNullOrWhiteSpace(input.PhoneNumber), (Owner u) => u.PhoneNumber.Contains(input.PhoneNumber.Trim()))
			.WhereIF(!string.IsNullOrWhiteSpace(input.Remark), (Owner u) => u.Remark.Contains(input.Remark.Trim()))
			.WhereIF(input.IsEnable.HasValue, (Owner u) => (int?)u.IsEnable == input.IsEnable);
		query = query.OrderBuilder(input);
		return await query.Select((Owner u) => new
		{
			Id = u.Id,
			Name = u.Name,
			PhoneNumber = u.PhoneNumber,
			CreateTime = u.CreateTime,
			Email = u.Email,
			IsEnable = u.IsEnable,
			Remark = u.Remark,
			TenantId = u.TenantId,
			RoomCount = (from r in SqlFunc.Subqueryable<Room>()
				where r.OwnerId == (long?)u.Id
				select r).Count()
		}).ToPagedListAsync(input.Page, input.PageSize);
	}

	[HttpPost("/owner/ownerExecl")]
	public async Task<IActionResult> ExportOwner([FromBody] OwnerInput input)
	{
		string str = "业主信息-" + DateTime.Now.ToString("yyyy-MM-dd");
		List<string> column = new List<string>();
		List<string> title = new List<string>();
		ISugarQueryable<Owner> query = _rep.Context.Queryable<Owner>().WhereIF(!string.IsNullOrWhiteSpace(input.Name), (Owner u) => u.Name.Contains(input.Name.Trim())).WhereIF(!string.IsNullOrWhiteSpace(input.PhoneNumber), (Owner u) => u.PhoneNumber.Contains(input.PhoneNumber.Trim()))
			.WhereIF(!string.IsNullOrWhiteSpace(input.Remark), (Owner u) => u.Remark.Contains(input.Remark.Trim()))
			.WhereIF(input.IsEnable.HasValue, (Owner u) => (int?)u.IsEnable == input.IsEnable);
		query = query.OrderBuilder(input);
		List<Owner> list = await query.ToListAsync();
		column.AddRange(new string[5] { "Name", "PhoneNumber", "Remark", "IsEnable", "CreateTime" });
		title.AddRange(new string[5] { "名称", "手机号", "备注", "状态", "创建日期" });
		MemoryStream memery = ExportToExcel.ExportToList(dic: new Dictionary<string, Dictionary<string, string>> { 
		{
			"IsEnable",
			new Dictionary<string, string>
			{
				{ "0", "禁用" },
				{ "1", "启用" }
			}
		} }, listInfo: list.ToArray(), headerText: str, sheetName: str, properName: column.ToArray(), titleName: title.ToArray());
		App.HttpContext.Response.ContentType = "application/vnd.ms-excel";
		byte[] aa = memery.ToArray();
		return new FileStreamResult(new MemoryStream(aa), "application/octet-stream")
		{
			FileDownloadName = str + ".xlsx"
		};
	}

	/// <summary>
	/// 增加业主
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/owner/add")]
	public async Task Add(AddOwnerInput input)
	{
		if (await (from u in _rep.Context.Queryable<Owner>().ClearFilter()
			where u.PhoneNumber == input.PhoneNumber
			select u).FirstAsync() != null)
		{
			throw Oops.Bah("手机号已被使用，请更换手机号");
		}
		Owner entity = input.Adapt<Owner>();
		entity.IsEnable = 1;
		entity.Password = MD5Encryption.Encrypt("123456");
		await _rep.InsertAsync(entity);
	}

	[HttpPost("/owner/addapp")]
	public async Task<Owner> AddApp(AddOwnerInput input)
	{
		if (await (from u in _rep.Context.Queryable<Owner>().ClearFilter()
			where u.PhoneNumber == input.PhoneNumber
			select u).FirstAsync() != null)
		{
			throw Oops.Bah("手机号已被使用，请更换手机号");
		}
		Owner entity = input.Adapt<Owner>();
		entity.IsEnable = 1;
		entity.Password = MD5Encryption.Encrypt("123456");
		return await _rep.InsertReturnEntityAsync(entity);
	}

	[HttpPost("/owner/switch")]
	public async Task Switch([FromQuery] long id, [FromQuery] int isEnable)
	{
		await (from it in _rep.Context.Updateable<Owner>().SetColumns((Owner it) => it.IsEnable == isEnable)
			where it.Id == id
			select it).ExecuteCommandAsync();
	}

	/// <summary>
	/// 删除业主
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/owner/delete")]
	public async Task Delete(DeleteOwnerInput input)
	{
		Owner entity = await _rep.GetFirstAsync((Owner u) => u.Id == input.Id);
		await _rep.DeleteAsync(entity);
		await (from u in _rep.Context.Updateable<Room>().SetColumns((Room u) => u.OwnerId == null)
			where u.OwnerId == (long?)entity.Id
			select u).ExecuteCommandAsync();
	}

	/// <summary>
	/// 更新业主
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/owner/edit")]
	public async Task Update(UpdateOwnerInput input)
	{
		if (await (from u in _rep.Context.Queryable<Owner>().ClearFilter()
			where u.Id != input.Id && u.PhoneNumber == input.PhoneNumber
			select u).FirstAsync() != null)
		{
			throw Oops.Bah("手机号已被使用，请更换手机号");
		}
		Owner entity = input.Adapt<Owner>();
		await _rep.Context.Updateable(entity).UpdateColumns((Owner it) => new { it.Name, it.PhoneNumber, it.Remark }).ExecuteCommandAsync();
	}

	/// <summary>
	/// 重置业主密码
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/owner/resetpassword")]
	public async Task ResetPassword(UpdateOwnerInput input)
	{
		string reset = MD5Encryption.Encrypt("123456");
		await (from it in _rep.Context.Updateable<Owner>().SetColumns((Owner it) => it.Password == reset)
			where it.Id == input.Id
			select it).ExecuteCommandAsync();
	}

	/// <summary>
	/// 获取业主
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpGet("/owner/detail")]
	public async Task<Owner> Get([FromQuery] QueryeOwnerInput input)
	{
		return await _rep.GetFirstAsync((Owner u) => u.Id == input.Id);
	}

	/// <summary>
	/// 获取业主列表
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpGet("/owner/list")]
	public async Task<dynamic> List([FromQuery] OwnerInput input)
	{
		return await _rep.AsQueryable().ToListAsync();
	}

	/// <summary>
	/// 未绑定房间，且可绑定房间，包含已绑定房间
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpGet("/owner/bindroom")]
	public async Task<dynamic> BindRoomData([FromQuery] QueryeOwnerInput input)
	{
		var result = (await (from w in _rep.Context.Queryable<Room>()
			where w.OwnerId == null || w.OwnerId == (long?)input.Id
			select w into s
			select new
			{
				key = s.Id,
				name = s.Name,
				build = from u in SqlFunc.Subqueryable<Building>()
					where u.Id == s.BuildingId
					select u.Name
			}).ToListAsync()).Select(s => new
		{
			key = s.key,
			label = s.build + "-" + s.name
		}).ToList();
		return new
		{
			data = result,
			rightValue = await (from w in _rep.Context.Queryable<Room>()
				where w.OwnerId == (long?)input.Id
				select w into s
				select s.Id).ToListAsync()
		};
	}

	/// <summary>
	/// 绑定房间
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/owner/bindroom")]
	public async Task BindRoom([FromBody] OwnerBindRoomInput input)
	{
		await (from w in _rep.Context.Updateable<Room>().SetColumns((Room s) => s.OwnerId == null)
			where w.OwnerId == (long?)input.Id
			select w).ExecuteCommandAsync();
		if (input.RoomId != null && input.RoomId.Count > 0)
		{
			await (from w in _rep.Context.Updateable<Room>().SetColumns((Room s) => s.OwnerId == (long?)input.Id)
				where input.RoomId.Contains(w.Id)
				select w).ExecuteCommandAsync();
		}
	}

	/// <summary>
	/// 获取业主消息通知
	/// </summary>
	/// <param name="page"></param>
	/// <param name="limit"></param>
	/// <returns></returns>
	[HttpGet("/owner/notices")]
	public async Task<dynamic> GetOwnerNotices(int page, int limit)
	{
		return await (from w in _rep.Context.Queryable<OwnerNotice>()
			where w.OwnerId == _userManager.UserId
			orderby w.CreateTime descending
			select w).ToPagedListAsync(page, limit);
	}

	/// <summary>
	/// 获取业主尚未阅读的消息数量
	/// </summary>
	/// <returns></returns>
	[HttpGet("/owner/unreadnotices")]
	public async Task<dynamic> GetUnReadNotice()
	{
		return await (from w in _rep.Context.Queryable<OwnerNotice>()
			where w.OwnerId == _userManager.UserId && w.Status == 0
			select w).CountAsync();
	}

	/// <summary>
	/// 获取未读消息内容
	/// </summary>
	/// <returns></returns>
	[HttpGet("/owner/unreadnoticelist")]
	public async Task<dynamic> GetUnReadNoticeList()
	{
		return await (from w in _rep.Context.Queryable<OwnerNotice>()
			where w.OwnerId == _userManager.UserId && w.Status == 0
			orderby w.CreateTime descending
			select w).Take(2).ToListAsync();
	}

	/// <summary>
	/// 消息阅读
	/// </summary>
	/// <param name="noticeId"></param>
	/// <returns></returns>
	[HttpPost("/owner/readnotice")]
	public async Task ReadNotice([FromQuery] long noticeId)
	{
		DateTime now = DateTime.Now;
		await (from w in _rep.Context.Updateable<OwnerNotice>().SetColumns((OwnerNotice w) => new OwnerNotice
			{
				Status = 1,
				ReadTime = now
			})
			where w.Id == noticeId && w.OwnerId == _userManager.UserId
			select w).ExecuteCommandAsync();
	}

	/// <summary>
	/// 导出列表excel
	/// </summary>
	/// <param name="input"></param>
	/// <returns></returns>
	[HttpPost("/owner/templeteexcel")]
	public async Task<IActionResult> Templeteexcel()
	{
		string str = "业主模板-" + DateTime.Now.ToString("yyyy-MM-dd");
		List<string> list = new List<string> { "业主名称", "手机号" };
		Dictionary<string, List<string>> dic = new Dictionary<string, List<string>>();
		ExcelUtil excelUtil = new ExcelUtil();
		MemoryStream stream = excelUtil.GetTemplate(list, dic, str);
		return new FileStreamResult(new MemoryStream(stream.ToArray()), "application/octet-stream")
		{
			FileDownloadName = str + ".xlsx"
		};
	}

	/// <summary>
	/// 上传文件
	/// </summary>
	/// <param name="file"></param>
	/// <param name="path"></param>
	/// <returns></returns>
	[HttpPost("/owner/uploadpdf")]
	public async Task UploadFile([Required] IFormFile file, string path = "")
	{
		try
		{
			ExcelUtil excelUtil = new ExcelUtil();
			List<AddOwnerInput> list = excelUtil.ExcelToList<AddOwnerInput>(file, new Dictionary<string, string>
			{
				{ "业主名称", "Name" },
				{ "手机号", "PhoneNumber" }
			});
			List<string> repeat = (from g in list
				group g by g.PhoneNumber into s
				select new
				{
					Key = s.Key,
					count = s.Count()
				} into w
				where w.count > 1
				select w into s
				select s.Key).ToList();
			if (repeat.Count > 0)
			{
				throw Oops.Bah("以下业主手机号重复：" + string.Join(',', repeat));
			}
			List<string> phones = list.Select((AddOwnerInput s) => s.PhoneNumber).ToList();
			List<string> hasphones = await (from u in _rep.Context.Queryable<Owner>().ClearFilter()
				where phones.Contains(u.PhoneNumber)
				select u.PhoneNumber).ToListAsync();
			if (hasphones.Count > 0)
			{
				throw Oops.Bah("以下手机号已被使用，请更换手机号：" + string.Join(',', hasphones));
			}
			List<Owner> owners = list.Adapt<List<Owner>>();
			string password = MD5Encryption.Encrypt("123456");
			foreach (Owner item in owners)
			{
				item.IsEnable = 1;
				item.Password = password;
			}
			await _rep.Context.Ado.BeginTranAsync();
			_rep.InsertRange(owners.ToArray());
			await _rep.Context.Ado.CommitTranAsync();
		}
		catch (Exception ex)
		{
			await _rep.Context.Ado.RollbackTranAsync();
			throw ex;
		}
	}
}
